﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RaygunDiplomacy
{
   public struct SpatialIndex
   {
      public static readonly SpatialIndex Zero = new SpatialIndex();

      public readonly int Row;
      public readonly int Column;
      public readonly int Layer;

      public SpatialIndex(int row, int column, int layer)
      {
         if (row < 0)
         {
            throw new ArgumentException("row");
         }
         if (column < 0)
         {
            throw new ArgumentException("column");
         }
         if (layer < 0)
         {
            throw new ArgumentException("sheet");
         }
         this.Row = row;
         this.Layer = layer;
         this.Column = column;
      }

      public bool OutOfRange<T>(T[, ,] cells)
      {
         return
            Row > cells.GetLength(0) ||
               Column > cells.GetLength(1) ||
               Layer > cells.GetLength(2);
      }

      public List<SpatialIndex> AdjacentIndices(SpatialIndex maxIndex)
      {
         return AdjacentIndices(maxIndex, Zero);
      }

      public List<SpatialIndex> AdjacentIndices(SpatialIndex maxIndex, SpatialIndex minIndex)
      {
         List<SpatialIndex> indices = new List<SpatialIndex>();

         if (minIndex.Row < Row)
         {
            indices.Add(new SpatialIndex(Row - 1, Column, Layer));
         }
         if (maxIndex.Row - 1 > Row)
         {
            indices.Add(new SpatialIndex(Row + 1, Column, Layer));
         }

         if (minIndex.Column < Column)
         {
            indices.Add(new SpatialIndex(Row, Column - 1, Layer));
         }
         if (maxIndex.Column - 1 > Column)
         {
            indices.Add(new SpatialIndex(Row, Column + 1, Layer));
         }

         if (minIndex.Layer < Layer)
         {
            indices.Add(new SpatialIndex(Row, Column, Layer - 1));
         }
         if (maxIndex.Layer - 1 > Layer)
         {
            indices.Add(new SpatialIndex(Row, Column, Layer + 1));
         }

         return indices;
      }

      public override bool Equals(object obj)
      {
         if (obj is SpatialIndex)
         {
            var other = (SpatialIndex)obj;

            return Row == other.Row && Column == other.Column && Layer == other.Layer;
         }

         return false;
      }

      public override int GetHashCode()
      {
         return (Row << 16) + (Column << 8) + Layer;
      }

      public static bool operator ==(SpatialIndex a, SpatialIndex b)
      {
         return a.Row == b.Row && a.Column == b.Column && a.Layer == b.Layer;
      }

      public static bool operator !=(SpatialIndex a, SpatialIndex b)
      {
         return a.Row != b.Row || a.Column != b.Column || a.Layer != b.Layer;
      }
   }
}